---
type: tutorial
title: Create a blog post archive
description: |-
  Tutorial: Build your first Astro blog —
  Use import.meta.glob() to access data from files in your project
i18nReady: true
---
import Box from '~/components/tutorial/Box.astro';
import Checklist from '~/components/Checklist.astro';
import MultipleChoice from '~/components/tutorial/MultipleChoice.astro';
import Option from '~/components/tutorial/Option.astro';
import PreCheck from '~/components/tutorial/PreCheck.astro';
import { Steps } from '@astrojs/starlight/components';

Now that you have a few blog posts to link to, it's time to configure the Blog page to create a list of them automatically!

<PreCheck>
  - Access data from all your posts at once using `import.meta.glob()`
  - Display a dynamically generated list of posts on your Blog page
  - Refactor to use a `<BlogPost />` component for each list item
</PreCheck>

## Dynamically display a list of posts

<Steps>
1. Add the following code to `blog.astro` to return information about all your Markdown files. `import.meta.glob()` will return an array of objects, one for each blog post.

    ```astro title="src/pages/blog.astro" ins={3}
    ---
    import BaseLayout from '../layouts/BaseLayout.astro'
    const allPosts = Object.values(import.meta.glob('./posts/*.md', { eager: true }));
    const pageTitle = "My Astro Learning Blog";
    ---
    <BaseLayout pageTitle={pageTitle}>
      <p>This is where I will post about my journey learning Astro.</p>
      <ul>
        <li><a href="/posts/post-1/">Post 1</a></li>
        <li><a href="/posts/post-2/">Post 2</a></li>
        <li><a href="/posts/post-3/">Post 3</a></li>
      </ul>
    </BaseLayout>
      ```


2. To generate the entire list of posts dynamically, using the post titles and URLs, replace your individual `<li>` tags with the following Astro code:

    ```astro title="src/pages/blog.astro" del={9,10,11} ins={13}
    ---
    import BaseLayout from '../layouts/BaseLayout.astro'
    const allPosts = Object.values(import.meta.glob('./posts/*.md', { eager: true }));
    const pageTitle = "My Astro Learning Blog";
    ---
    <BaseLayout pageTitle={pageTitle}>
      <p>This is where I will post about my journey learning Astro.</p>
      <ul>
        <li><a href="/posts/post-1/">Post 1</a></li>
        <li><a href="/posts/post-2/">Post 2</a></li>
        <li><a href="/posts/post-3/">Post 3</a></li>

        {allPosts.map((post: any) => <li><a href={post.url}>{post.frontmatter.title}</a></li>)}
      </ul>
    </BaseLayout>
    ```

    Your entire list of blog posts is now being generated dynamically using Astro's built-in TypeScript support, by mapping over the array returned by `import.meta.glob()`.

3. Add a new blog post by creating a new `post-4.md` file in `src/pages/posts/` and adding some Markdown content. Be sure to include at least the frontmatter properties used below.

    ```markdown
    ---
    layout: ../../layouts/MarkdownPostLayout.astro
    title: My Fourth Blog Post
    author: Astro Learner
    description: "This post will show up on its own!"
    image: 
        url: "https://docs.astro.build/default-og-image.png"
        alt: "The word astro against an illustration of planets and stars."
    pubDate: 2022-08-08
    tags: ["astro", "successes"]
    ---
    This post should show up with my other blog posts, because `import.meta.glob()` is returning a list of all my posts in order to create my list.
    ```

4. Revisit your blog page in your browser preview at `http://localhost:4321/blog` and look for an updated list with four items, including your new blog post!
</Steps>

<Box icon="puzzle-piece">

## Challenge: Create a BlogPost component

Try on your own to make all the necessary changes to your Astro project so that you can instead use the following code to generate your list of blog posts:

```astro title="src/pages/blog.astro" del={2} ins={3}
<ul>
  {allPosts.map((post: any) => <li><a href={post.url}>{post.frontmatter.title}</a></li>)}
  {allPosts.map((post: any) => <BlogPost url={post.url} title={post.frontmatter.title} />)}
</ul>
```

<details>
<summary>Expand to see the steps</summary>

<Steps>
1. Create a new component in `src/components/`.

    <details>
    <summary>Show the filename</summary>
    ```
    BlogPost.astro
    ```
    </details>

2. Write the line of code in your component so that it will be able to receive a `title` and `url` as `Astro.props`.

    <details>
    <summary>Show the code</summary>
    ```astro
    ---
    // src/components/BlogPost.astro
    const { title, url } = Astro.props;
    ---
    ```
    </details>

3. Add the templating used to create each item in your blog post list.

    <details>
    <summary>Show the code</summary>
    ```astro
    <!-- src/components/BlogPost.astro -->
    <li><a href={url}>{title}</a></li>
    ```
    </details>

4. Import the new component into your Blog page.

    <details>
    <summary>Show the code</summary>
    ```astro title="src/pages/blog.astro" ins={3}
    ---
    import BaseLayout from '../layouts/BaseLayout.astro';
    import BlogPost from '../components/BlogPost.astro';
    const allPosts = Object.values(import.meta.glob('../pages/posts/*.md', { eager: true }));
    const pageTitle = "My Astro Learning Blog";
    ---
    ```
    </details>

5. Check Yourself: see the finished component code.

    <details>
    <summary>Show the code</summary>
    ```astro title="src/components/BlogPost.astro"
    ---
    const { title, url } = Astro.props
    ---
    <li><a href={url}>{title}</a></li>
    ```
    ```astro title="src/pages/blog.astro" ins={3,10}
    ---
    import BaseLayout from '../layouts/BaseLayout.astro';
    import BlogPost from '../components/BlogPost.astro';
    const allPosts = Object.values(import.meta.glob('../pages/posts/*.md', { eager: true }));
    const pageTitle = "My Astro Learning Blog"
    ---
    <BaseLayout pageTitle={pageTitle}>
      <p>This is where I will post about my journey learning Astro.</p>
      <ul>
        {allPosts.map((post: any) => <BlogPost url={post.url} title={post.frontmatter.title} />)}
      </ul>
    </BaseLayout>
    ```
    </details>
</Steps>
</details>
</Box>



<Box icon="question-mark">

### Test your knowledge

If your Astro component contains the following line of code: 

```astro
---
const myPosts = Object.values(import.meta.glob('./posts/*.md', { eager:  true }));
---
```

Choose the syntax you could write to represent:

1. The title of your third blog post.  

    <MultipleChoice>
      <Option>
        `myPosts.map((post) => <LastUpdated date={post.frontmatter.pubDate} />)`
      </Option>
      <Option isCorrect>
        `myPosts[2].frontmatter.title`
      </Option>
      <Option>
        `<a href={myPosts[0].url}>First Post!!</a>`
      </Option>
    </MultipleChoice>

2. A link to the URL of your first blog post. 

    <MultipleChoice>
      <Option>
        `myPosts.map((post) => <LastUpdated date={post.frontmatter.pubDate} />)`
      </Option>
      <Option>
        `myPosts[2].frontmatter.title`
      </Option>
      <Option isCorrect>
        `<a href={myPosts[0].url}>First Post!!</a>`
      </Option>
    </MultipleChoice>

3. A component for each post, displaying the date that it was last updated.

    <MultipleChoice>
      <Option isCorrect>
        `myPosts.map((post) => <LastUpdated date={post.frontmatter.pubDate} />)`
      </Option>
      <Option>
        `myPosts[2].frontmatter.title`
      </Option>
      <Option>
        `<a href={myPosts[0].url}>First Post!!</a>`
      </Option>
    </MultipleChoice>

</Box>

## Checklist

<Box icon="check-list">

<Checklist>
- [ ] I can query for data from my local files.
- [ ] I can display a list of all my blog posts.
</Checklist>
</Box>

### Resources

- [Importing glob patterns in Astro](/en/guides/imports/#importmetaglob)
